
import 'package:cross_file/cross_file.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/types/camera_device.dart';
import 'package:image_picker/types/image_options.dart';
import 'package:image_picker/types/image_source.dart';
import 'package:image_picker/types/lost_data_response.dart';
import 'package:image_picker/types/retrieve_type.dart';

import 'image_picker_platform_interface.dart';
import 'messages.g.dart';

class ImagePicker extends ImagePickerPlatform{

  ImagePicker({@visibleForTesting ImagePickerApi? api})
      : _hostApi = api ?? ImagePickerApi();

  final ImagePickerApi _hostApi;
  bool useOhosPhotoPicker = true;
  static void registerWith() {
    ImagePickerPlatform.instance = ImagePicker();
  }

  @override
  Future<XFile?> getImage({
    String? imageType,
    double? maxWidth,
    double? maxHeight,
    int? imageQuality,
    int? recommendationType,
    CameraDevice preferredCameraDevice = CameraDevice.rear,
  }) async {
    final String? path = await _getImagePath(
      imageType: imageType,
      maxWidth: maxWidth,
      maxHeight: maxHeight,
      imageQuality: imageQuality,
      recommendationType: recommendationType,
      preferredCameraDevice: preferredCameraDevice,
    );
    return path != null ? XFile(path) : null;
  }

  @override
  Future<XFile?> getImageFromSource({
    ImagePickerOptions options = const ImagePickerOptions(),
  }) async {
    final String? path = await _getImagePath(
      maxHeight: options.maxHeight,
      maxWidth: options.maxWidth,
      imageQuality: options.imageQuality,
      //recommendationType: options.recommendationType,
      preferredCameraDevice: options.preferredCameraDevice,
      requestFullMetadata: options.requestFullMetadata,
    );
    return path != null ? XFile(path) : null;
  }

  @override
  Future<List<XFile>?> getMultiImage({
    String? imageType,
    double? maxWidth,
    double? maxHeight,
    int? imageQuality,
    int? recommendationType,
  }) async {
    final List<dynamic> paths = await _getMultiImagePath(
      imageType: imageType,
      maxWidth: maxWidth,
      maxHeight: maxHeight,
      imageQuality: imageQuality,
      recommendationType: recommendationType,
    );
    if (paths.isEmpty) {
      return null;
    }

    return paths.map((dynamic path) => XFile(path as String)).toList();
  }

  @override
  Future<LostDataResponse> getLostData() async {
    final CacheRetrievalResult? result = await _hostApi.retrieveLostResults();

    if (result == null) {
      return LostDataResponse.empty();
    }

    assert(result.paths.isEmpty != (result.error == null));

    final CacheRetrievalError? error = result.error;
    final PlatformException? exception = error == null
        ? null
        : PlatformException(code: error.code, message: error.message);
    final List<XFile> pickedFileList =
    result.paths.map((String? path) => XFile(path!)).toList();

    return LostDataResponse(
      file: pickedFileList.isEmpty ? null : pickedFileList.last,
      exception: exception,
      type: _retrieveTypeForCacheType(result.type),
      files: pickedFileList,
    );
  }

  Future<List<dynamic>> _getMultiImagePath({
    String? imageType,
    double? maxWidth,
    double? maxHeight,
    int? imageQuality,
    int? recommendationType,
  }) async {
    if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
      throw ArgumentError.value(
          imageQuality, 'imageQuality', 'must be between 0 and 100');
    }

    if (maxWidth != null && maxWidth < 0) {
      throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative');
    }

    if (maxHeight != null && maxHeight < 0) {
      throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative');
    }

    final List<String?> path = await _hostApi.pickImages(
      //SourceSpecification(type: SourceType.gallery),
      ImageSelectionOptions(
        maxWidth: maxWidth,
        maxHeight: maxHeight,
        quality: imageQuality ?? 100,
        recommendationType: recommendationType ?? 0,
      ),
      GeneralOptions(
          allowMultiple: true, usePhotoPicker: useOhosPhotoPicker, imageType: imageType),
    );

    List<String?> pathList = [];

    for(int i = 0 ; i<path.length; i+=2){
      pathList.add(path[i]);
    }

    return pathList;
  }

  Future<String?> _getImagePath({
    String? imageType,
    double? maxWidth,
    double? maxHeight,
    int? imageQuality,
    int? recommendationType,
    CameraDevice preferredCameraDevice = CameraDevice.rear,
    bool requestFullMetadata = true,
  }) async {
    if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
      throw ArgumentError.value(
          imageQuality, 'imageQuality', 'must be between 0 and 100');
    }

    if (maxWidth != null && maxWidth < 0) {
      throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative');
    }

    if (maxHeight != null && maxHeight < 0) {
      throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative');
    }

    final List<String?> paths = await _hostApi.pickImages(
      //_buildSourceSpec(source, preferredCameraDevice),
      ImageSelectionOptions(
        maxWidth: maxWidth,
        maxHeight: maxHeight,
        quality: imageQuality ?? 100,
        recommendationType: recommendationType ?? 0,
      ),
      GeneralOptions(
        allowMultiple: false,
        usePhotoPicker: useOhosPhotoPicker,
        imageType: imageType,
      ),
    );
    return paths.isEmpty ? null : paths.first;
  }

  RetrieveType _retrieveTypeForCacheType(CacheRetrievalType type) {
    switch (type) {
      case CacheRetrievalType.image:
        return RetrieveType.image;
      case CacheRetrievalType.video:
        return RetrieveType.video;
    }
  }
}
